﻿package crochet.core.configuration;

/*
 Copyright 2011 Intuitive Solutions

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;

public class CrochetConfiguration {
	private static CrochetConfiguration mcInstance = null;

	HashMap<String, CrochetConfigurationElement> hmImmediateSchedulerMap,
			hmThreadPoolSchedulerMap, hmExecutionPoolSchedulerMap,
			hmTimerSchedulerMap, hmRescheduleOnExceptionPolicyMap,
			hmRetryOnExceptionPolicyMap;

	protected CrochetConfiguration() {
		hmImmediateSchedulerMap = new HashMap<String, CrochetConfigurationElement>();
		hmThreadPoolSchedulerMap = new HashMap<String, CrochetConfigurationElement>();
		hmExecutionPoolSchedulerMap = new HashMap<String, CrochetConfigurationElement>();
		hmTimerSchedulerMap = new HashMap<String, CrochetConfigurationElement>();
		hmRescheduleOnExceptionPolicyMap = new HashMap<String, CrochetConfigurationElement>();
		hmRetryOnExceptionPolicyMap = new HashMap<String, CrochetConfigurationElement>();

		initialize();
	}

	public static CrochetConfiguration getInstance() {
		if (mcInstance == null) {
			mcInstance = new CrochetConfiguration();
		}

		return mcInstance;

	}

	private void initialize() {
		Properties props = new Properties();
		//ClassLoader cl = ClassLoader.getSystemClassLoader();
		ClassLoader cl = CrochetConfiguration.class.getClassLoader();
		InputStream isStream = cl.getResourceAsStream("crochet.properties");

		if (isStream != null) {
			try {
				props.load(isStream);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				// e.printStackTrace();
			}
			for (String sKey : props.stringPropertyNames()) {
				String s = props.getProperty(sKey);

				int i = 0;

				String sElementTypeName, sElementName, sPropertyName;

				sElementTypeName = sKey.replace("crochet.", "");
				sElementTypeName = sElementTypeName.substring(0,
						sElementTypeName.indexOf("."));

				sElementName = sKey.replace(
						"crochet." + sElementTypeName + ".", "");
				sElementName = sElementName.substring(0,
						sElementName.indexOf("."));

				sPropertyName = sKey.substring(sKey.lastIndexOf(".") + 1);

				if ("retryOnExceptionPolicy".equals(sElementTypeName)) {
					RetryOnExceptionElement ceConfigurationelement = null;
					ceConfigurationelement = (RetryOnExceptionElement) getConfigurationElement(
							hmRetryOnExceptionPolicyMap,
							RetryOnExceptionElement.class, sElementName);

					if ("retries".equals(sPropertyName)) {
						ceConfigurationelement.setRetries(Integer.parseInt(s));
					} else if ("delay".equals(sPropertyName)) {
						ceConfigurationelement.setDelay(Integer.parseInt(s));
					} else if ("forceThrow".equals(sPropertyName)) {
						ceConfigurationelement.setForceThrow(Boolean
								.parseBoolean(s));
					}
				} else if ("rescheduleOnException".equals(sElementTypeName)) {
					RescheduleOnExceptionElement ceConfigurationelement = null;
					ceConfigurationelement = (RescheduleOnExceptionElement) getConfigurationElement(
							hmRescheduleOnExceptionPolicyMap,
							RescheduleOnExceptionElement.class, sElementName);

					if ("reschedules".equals(sPropertyName)) {
						ceConfigurationelement.setRetries(Integer.parseInt(s));
					} else if ("delay".equals(sPropertyName)) {
						ceConfigurationelement.setDelay(Integer.parseInt(s));
					} else if ("forceThrow".equals(sPropertyName)) {
						ceConfigurationelement.setForceThrow(Boolean
								.parseBoolean(s));
					}
				} else if ("immediate".equals(sElementTypeName)) {
					ImmediateSchedulerElement ceConfigurationelement = null;
					ceConfigurationelement = (ImmediateSchedulerElement) getConfigurationElement(
							hmImmediateSchedulerMap,
							ImmediateSchedulerElement.class, sElementName);

					if ("policy".equals(sPropertyName)) {
						ceConfigurationelement.setPolicyName(s);
					}
				}
				/*
				 * else if("timer".equals(sElementTypeName)) {
				 * 
				 * }
				 */
				else if ("threadPool".equals(sElementTypeName)) {
					ThreadPoolSchedulerElement ceConfigurationelement = null;
					ceConfigurationelement = (ThreadPoolSchedulerElement) getConfigurationElement(
							hmThreadPoolSchedulerMap,
							ThreadPoolSchedulerElement.class, sElementName);

					if ("policy".equals(sPropertyName)) {
						ceConfigurationelement.setPolicyName(s);
					} else if ("poolSize".equals(sPropertyName)) {
						ceConfigurationelement.setPoolSize(Integer.parseInt(s));
					}
				} else if ("executionPool".equals(sElementTypeName)) {
					ExecutionPoolSchedulerElement ceConfigurationelement = null;
					ceConfigurationelement = (ExecutionPoolSchedulerElement) getConfigurationElement(
							hmExecutionPoolSchedulerMap,
							ExecutionPoolSchedulerElement.class, sElementName);

					if ("policy".equals(sPropertyName)) {
						ceConfigurationelement.setPolicyName(s);
					} else if ("poolSize".equals(sPropertyName)) {
						ceConfigurationelement.setPoolSize(Integer.parseInt(s));
					}
				}
			}
		}
	}

	private CrochetConfigurationElement getConfigurationElement(
			HashMap<String, CrochetConfigurationElement> hmelementsMap,
			Class<?> cClassType, String sElementName) {
		CrochetConfigurationElement cceCrochetConfigurationElement = null;
		if (hmelementsMap.containsKey(sElementName)) {
			cceCrochetConfigurationElement = (CrochetConfigurationElement) hmelementsMap
					.get(sElementName);
		} else {
			try {
				cceCrochetConfigurationElement = (CrochetConfigurationElement) cClassType
						.newInstance();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			cceCrochetConfigurationElement.setName(sElementName);

			hmelementsMap.put(sElementName, cceCrochetConfigurationElement);
		}
		return cceCrochetConfigurationElement;
	}

	/*
	 * private CrochetConfigurationElement
	 * getConfigurationElement(HashMap<String, CrochetConfigurationElement>
	 * hmElementsMap, ){
	 * 
	 * }
	 */

	public ImmediateSchedulerElement getImmediateSchedulers(String sName) {
		return (ImmediateSchedulerElement) hmImmediateSchedulerMap.get(sName);
	}

	public ThreadPoolSchedulerElement getThreadPoolSchedulers(String sName) {

		return (ThreadPoolSchedulerElement) hmThreadPoolSchedulerMap.get(sName);
	}

	public ExecutionPoolSchedulerElement getExecutionPoolSchedulers(String sName) {
		return (ExecutionPoolSchedulerElement) hmExecutionPoolSchedulerMap
				.get(sName);
	}

	/*
	 * public TimerSchedulerElement getTimerSchedulers(String sName) { return
	 * (TimerSchedulerElement)hmtimer.get(sName); }
	 */

	public RescheduleOnExceptionElement getRescheduleOnExceptionPolicies(
			String sName) {
		return (RescheduleOnExceptionElement) hmRescheduleOnExceptionPolicyMap
				.get(sName);
	}

	public RetryOnExceptionElement getRetryOnExceptionPolicies(String sName) {
		return (RetryOnExceptionElement) hmRetryOnExceptionPolicyMap.get(sName);
	}

	public CrochetConfigurationElement GetPolicyElement(String sPolicyName) {
		CrochetConfigurationElement cceCrochetConfigurationElement = null;

		if (sPolicyName != null && !"".equals(sPolicyName.trim())) {
			cceCrochetConfigurationElement = hmRetryOnExceptionPolicyMap
					.get(sPolicyName);

			if (cceCrochetConfigurationElement == null) {
				cceCrochetConfigurationElement = hmRescheduleOnExceptionPolicyMap
						.get(sPolicyName);
			}
		}

		return cceCrochetConfigurationElement;
	}
}
